﻿using System;
using System.Collections.Generic;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.ServiceComponent.Monitor.Client;
using T.ServiceComponent.Kernel.Service;
using T.FAS.Runtime.Base.Common;
using T.ServiceComponent.Error;
using ExceptionHelper = T.FAS.Runtime.Base.Common.ExceptionHelper;

namespace T.FAS.Runtime.DataAccess.Common
{
    public class DQMonitor
    {
        private const string tag_DQ = "DQCode";
        private static readonly string s_applicationTagName = "ProcessName";

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dq"></param>
        public static void MonitorTPS(DataQuery dq, Exception e = null)
        {
            string monitorMetaID = DQMonitorConst.Instance.TPS;
            Dictionary<string, string> tags = new Dictionary<string, string> { { "DQCode", $"{dq.Code}" } };
            Dictionary<string, string> context = new Dictionary<string, string> { { s_applicationTagName, ContextInfo.ApplicationName } };
            if (e != null)
            {
                context.Add("ExceptionMessage", e.Message);
                context.Add("ExceptionStack", e.GetFullStackTrace());
                context.Add("InvokeResult", "Error");
            }
            MonitorClient.Send(monitorMetaID, 1, tags, context);
        }

        public static void MonitorNoFilter(DataQuery dq, Exception e = null)
        {
            string monitorMetaID = DQMonitorConst.Instance.NoFilter;
            Dictionary<string, string> tags = new Dictionary<string, string> { { "DQCode", $"{dq.Code}" } };
            Dictionary<string, string> context = new Dictionary<string, string> { { s_applicationTagName, ContextInfo.ApplicationName } };
            if (e != null)
            {
                context.Add("ExceptionMessage", e.Message);
                context.Add("ExceptionStack", e.GetFullStackTrace());
                context.Add("InvokeResult", "Error");
            }
            MonitorClient.Send(monitorMetaID, 1, tags, context);
        }

        public static void MonitorDuration(DataQuery dq, double duration, Exception e = null)
        {
            string monitorMetaID = DQMonitorConst.Instance.Duration;
            Dictionary<string, string> tags = new Dictionary<string, string> { { "DQCode", $"{dq.Code}" } };
            Dictionary<string, string> context = new Dictionary<string, string> { { s_applicationTagName, ContextInfo.ApplicationName } };
            if (e != null)
            {
                context.Add("ExceptionMessage", e.Message);
                context.Add("ExceptionStack", e.GetFullStackTrace());
                context.Add("InvokeResult", "Error");
            }
            MonitorClient.Send(monitorMetaID, duration, tags, context);
        }

        public static void MonitorTrace(DataQuery dq, DateTime start, Exception e = null)
        {
            try
            {
                var endTime = DateTime.Now;
                var span = endTime - start;
                var requestID = RpcContext.Current.RequestID;
                var rpcID = RpcContext.Current.RpcID;
                var longValues = new Dictionary<string, long>(StringComparer.OrdinalIgnoreCase);
                var doubleValues = new Dictionary<string, double>() { { "TimeSpan", span.TotalMilliseconds } };
                var tags = new Dictionary<string, string>
                {
                    { s_applicationTagName, ContextInfo.ApplicationName }
                };
                var context = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
                {
                    { "RpcID", rpcID },
                    { "RequestID", requestID },
                    { "TraceType", "DQ" },
                    { "HostName", FASContextHelper.GetInstance().HostName },
                    { "ProcessName", FASContextHelper.GetInstance().ProcessName },
                    { tag_DQ, $"{dq.Code}" },
                    { "ServiceID", "DQService"},
                    { "BeginTime", start.ToString("yyyy-MM-dd HH:mm:ss.fff") },
                    { "EndTime", endTime.ToString("yyyy-MM-dd HH:mm:ss.fff") }
                };

                if (e != null)
                {
                    context.Add("InvokeResult", "Error");
                    context.Add("ExceptionMessage", e.Message);
                    context.Add("ExceptionStack", e.GetFullStackTrace());
                }
                else
                {
                    context.Add("InvokeResult", "OK");
                }

                MonitorClient.Trace(requestID, rpcID, longValues, doubleValues, tags, context);
            }
            catch (Exception exp)
            {
                LocalLogService.WriteError(exp, $"DQ:{dq?.Code}全链路上报失败，msg:{exp.Message}");
            }
        }

        /// <summary>
        /// 上报根因
        /// </summary>
        /// <param name="dq"></param>
        /// <param name="start"></param>
        /// <param name="e"></param>
        public static void RootCaseReport(DataQuery dq, DateTime start, Exception e)
        {
            if (e == null)
                return;
            var ex = ExceptionHelper.GetLastError(e);
            if (ex == null)
                return;
            //如果是远程异常，不上报异常根因监控
            if (ExceptionHelper.IsRemoteException(e))
                return;
            var requestID = RpcContext.Current.RequestID;
            var rpcID = RpcContext.Current.RpcID;
            var endTime = DateTime.Now;
            Dictionary<string, string> tags = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            Dictionary<string, string> context = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            try
            {
                //Tag：程序信息
                tags.Add("HostID", FASContextHelper.GetInstance().HostID);            //异常发生地
                tags.Add("HostType", FASContextHelper.GetInstance().HostType);        //异常发生地
                tags.Add("ClientIP", FASContextHelper.GetInstance().HostName);        //异常发生地
                tags.Add("ServerIP", ExceptionHelper.GetTargetFromContext(e));        //程序访问的远程目标地址

                //Tag：服务信息
                tags.Add(tag_DQ, dq.Code);                                              //DQ标识
                tags.Add("SourceServiceID", dq.Code + ":owner_" + dq.LastModifier);     //海哥提供的异常根因上报，获取负责人的写法，DQ标识 + 负责人

                //Tag：异常信息
                tags.Add("ErrorType", Convert.ToString(ex.GetType()));
                tags.Add("ErrorMessage", ex.Message);
                tags.Add("ErrorCode", ex is TException eee ? eee.Code : "");
                tags.Add("ErrorSource", ex.Source);
                tags.Add("ErrorLevel", ExceptionHelper.GetErrorLevel(ex));

                //Context：全链路信息
                context.Add("RequestID", requestID);
                context.Add("RpcID", rpcID);
                context.Add("TraceType", "DQ");
                context.Add("BeginTime", start.ToString("yyyy-MM-dd HH:mm:ss.fff"));
                context.Add("EndTime", endTime.ToString("yyyy-MM-dd HH:mm:ss.fff"));
                context.Add("ProcessName", FASContextHelper.GetInstance().ProcessName);

                MonitorClient.Send(FASContextHelper.GetInstance().RootCaseMonitorMetaData, 1, tags, context);
            }
            catch
            { }
        }
    }
}